package com.study.collectors;


import com.study.collectors.Bean.BrowsingHistoryBO;
import com.study.collectors.Bean.Student;
import org.junit.Test;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @program: java8
 * @description: 终止操作Collectors类的用法
 * @author: yangyb
 * @create: 2021-12-07 14:31
 **/

public class CollectionTest {

    @Test
    public void test() {
        List<String> list = Arrays.asList("123", "456", "789", "1101", "212121121", "asdaa", "3e3e3e", "2321eew", "123");
        System.out.println("原list为=" + list);
        List<String> toCollection = list.stream().collect(Collectors.toCollection(LinkedList::new));
        Set<String> toSet = list.stream().collect(Collectors.toSet());
        System.out.println("toCollection()用法=" + toCollection);
        System.out.println("toSet()用法=" + toSet);

    }

    @Test
    public void joiningTest() {
        List<String> list = Arrays.asList("123", "456", "789", "1101", "212121121", "asdaa", "3e3e3e", "2321eew", "123");
        // 无参方法
        String s = list.stream().collect(Collectors.joining());
        // 指定连接符
        String ss = list.stream().collect(Collectors.joining("-"));
        // 指定连接符和前后缀
        String sss = list.stream().collect(Collectors.joining("-", "S", "E"));

        System.out.println("无参方法用法=" + s);
        System.out.println("指定连接符用法=" + ss);
        System.out.println("指定连接符和前后缀用法=" + sss);
    }

    @Test
    public void mappingTest() {
        List<String> list = Arrays.asList("123", "456", "789", "1101", "212121121", "asdaa", "3e3e3e", "2321eew", "123");
        //Collectors中mapping的用法（经字符串转换为BigDecimal,再做规约reduce处理）
        BigDecimal BigDecimalList = list.stream().limit(5).collect(Collectors.mapping(BigDecimal::new, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)));
        //stream中reduce用法
        BigDecimal reduce = list.stream().limit(5).map(BigDecimal::new).reduce(BigDecimal.ZERO, BigDecimal::add);

        System.out.println("mapping用法=" + BigDecimalList);
        System.out.println("stream中reduce用法=" + reduce);


    }

    @Test
    public void collectingAndThenTest() {
        // 比如我们将list joining 然后转成大写
        List<String> list = Arrays.asList("123", "456", "789", "1101", "212121121", "asdaa", "3e3e3e", "2321eew", "123");
        String collectingAndThen = list.stream().collect(Collectors.collectingAndThen(Collectors.joining("-"), String::toUpperCase));
        String collect = list.stream().limit(5).collect(Collectors.collectingAndThen(Collectors.mapping(BigDecimal::new,
                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)), BigDecimal::toString));

        System.out.println("collectingAndThen方法=" + collectingAndThen);


    }

    @Test
    public void maxByTest() {
        List<String> list = Arrays.asList("123", "456", "789", "1101", "212121121", "asdaa", "3e3e3e", "2321eewrrrrrre",
                "123");
        Optional<String> optionalMax = list.stream().collect(Collectors.maxBy(Comparator.comparingInt(String::length)));
        Optional<String> optionalMin = list.stream().collect(Collectors.minBy(Comparator.comparingInt(String::length)));
        System.out.println("maxBy方法" + optionalMax.get());
        System.out.println("minBy方法" + optionalMin.get());

        List<String> listNumber = Arrays.asList("123", "456", "789", "1101", "212121121");
        Optional<Integer> integer = listNumber.stream().map(Integer::valueOf).collect(Collectors.maxBy(Comparator.naturalOrder()));
        Optional<Integer> max = listNumber.stream().map(Integer::valueOf).max(Comparator.naturalOrder());

        System.out.println("maxBy方法最大值：" + integer.get());
        System.out.println("max方法最大值：" + max.get());

    }

    @Test
    public void summingTest() {
        List<String> list = Arrays.asList("123", "456", "789", "1101", "212121121", "asdaa", "3e3e3e", "2321eewr", "123");
        int i = list.stream().limit(3).collect(Collectors.summingInt(Integer::valueOf));
        long l = list.stream().limit(3).collect(Collectors.summingLong(Long::valueOf));
        double d = list.stream().limit(3).collect(Collectors.summingDouble(Double::valueOf));
        System.out.println("summingInt方法:" + i);
        System.out.println("summingLong方法:" + l);
        System.out.println("summingDouble方法:" + d);

    }

    @Test
    public void averagingTest() {
        List<String> list = Arrays.asList("123", "456", "789", "1101", "212121121", "asdaa", "3e3e3e", "2321eewr", "123");
        double i = list.stream().limit(3).collect(Collectors.averagingInt(Integer::valueOf));
        double l = list.stream().limit(3).collect(Collectors.averagingLong(Long::valueOf));
        double d = list.stream().limit(3).collect(Collectors.averagingDouble(Double::valueOf));
        System.out.println("averagingInt方法:" + i);
        System.out.println("averagingLong方法:" + l);
        System.out.println("averagingDouble方法:" + d);

    }

    @Test
    public void reducingTest() {
        List<String> list = Arrays.asList("123", "456", "789", "1101", "212121121", "asdaa", "3e3e3e", "2321eewr", "123");
        Optional<Integer> optionalSum = list.stream().limit(5).map(Integer::valueOf).collect(Collectors.reducing(Integer::sum));
        Integer integerStart = list.stream().limit(5).map(Integer::valueOf).collect(Collectors.reducing(0, Integer::sum));
        Integer integer = list.stream().limit(5).collect(Collectors.reducing(0, Integer::valueOf, Integer::sum));

        Integer reduceStream = list.stream().limit(5).map(Integer::valueOf).reduce(0, Integer::sum);

        System.out.println("无初始的情况:" + optionalSum);
        System.out.println("有初始的情况:" + integerStart);
        System.out.println("有初始的情况且先对元素转换再reduce:" + integer);

        System.out.println("Stream流中的reduce:" + reduceStream);


    }

    @Test
    public void groupingByTest() {
        List<String> list = Arrays.asList("123", "456", "789", "1101", "212121121", "asdaa", "3e3e3e", "2321eewr", "123");
        Map<Integer, List<String>> s = list.stream().collect(Collectors.groupingBy(String::length));
        // 在上面方法的基础上增加了对流中元素的处理方式的Collector，比如上面的默认的处理方法就是Collectors.toList()
        Map<Integer, List<String>> ss = list.stream().collect(Collectors.groupingBy(String::length, Collectors.toList()));
        // 在第二个方法的基础上再添加了结果Map的生成方法。
        Map<Integer, Set<String>> sss = list.stream().collect(Collectors.groupingBy(String::length, HashMap::new,
                Collectors.toSet()));

        Map<Integer, Set<String>> set = list.stream().collect(Collectors.groupingBy(String::length,
                Collectors.toSet()));

        System.out.println("按照字符串长度分组" + "分组函数" + s);
        System.out.println("分组函数+默认处理方式Collectors.toList()" + ss);
        System.out.println("分组函数+map+处理方式Collectors.toSet()" + sss);
        System.out.println("分组函数+处理方式Collectors.toSet()去重" + set);


    }

    @Test
    public void partitioningByTest() {
        List<String> list = Arrays.asList("123", "456", "789", "1101", "212121121", "asdaa", "3e3e3e", "2321eewr", "123");
        Map<Boolean, List<String>> partitioningByList = list.stream().collect(Collectors.partitioningBy(e -> e.length() > 5));
        Map<Boolean, Set<String>> partitioningBySet = list.stream().collect(Collectors.partitioningBy(e -> e.length() > 5, Collectors.toSet()));

        System.out.println("分区函数" + partitioningByList);
        System.out.println("分组函数+处理方式Collectors.toSet()" + partitioningBySet);


    }

    @Test
    public void toMapTest() {
        List<String> list = Arrays.asList("123", "456", "789", "1101", "212121121", "asdaa", "3e3e3e", "2321eewr", "123");
        Map<String, String> map = list.stream().limit(3).collect(Collectors.toMap(e -> e.substring(0, 1), e -> e));
        Map<String, String> map1 = list.stream().collect(Collectors.toMap(e -> e.substring(0, 1), e -> e, (a, b) -> b));
        Map<String, String> map2 = list.stream().collect(Collectors.toMap(e -> e.substring(0, 1), e -> e, (a, b) -> b, HashMap::new));

        System.out.println(map);
        System.out.println(map1);
        System.out.println(map2);

    }

    @Test
    public void toMapTestReal() {
        BrowsingHistoryBO historyBO = new BrowsingHistoryBO();
        historyBO.setBrowsId(12345L);
        historyBO.setContext("dsdddsd");
        historyBO.setDateTime("2022-02-08");
        historyBO.setPerson("张三");

        BrowsingHistoryBO historyBO2 = new BrowsingHistoryBO();
        historyBO2.setBrowsId(12365L);
        historyBO2.setContext("微微儿");
        historyBO2.setDateTime("2022-09-23");
        historyBO2.setPerson("张三");

        BrowsingHistoryBO historyBO3 = new BrowsingHistoryBO();
        historyBO3.setBrowsId(12375L);
        historyBO3.setContext("得到的");
        historyBO3.setDateTime("2023-08-03");
        historyBO3.setPerson("李四");

        BrowsingHistoryBO historyBO4 = new BrowsingHistoryBO();
        historyBO4.setBrowsId(12385L);
        historyBO4.setContext("都是错的");
        historyBO4.setDateTime("2019-09-05");
        historyBO4.setPerson("李四");

        List<BrowsingHistoryBO> list = new ArrayList<>();
        list.add(historyBO);
        list.add(historyBO2);
        list.add(historyBO3);
        list.add(historyBO4);

        //情景一：获取最近一次的浏览记录
        Optional<BrowsingHistoryBO> first = list.stream().sorted(Comparator.comparing(BrowsingHistoryBO::getDateTime).reversed()).findFirst();
        System.out.println("获取最近一次的浏览记录:" + first);
        //情景二：按照浏览时间排序(从远到近)
        List<BrowsingHistoryBO> historyBOList = list.stream().sorted(Comparator.comparing(BrowsingHistoryBO::getDateTime)).collect(Collectors.toList());
        System.out.println("按照浏览时间排序(从远到近):" + historyBOList);
        //情景三：获取每个人最近的浏览记录
        System.out.println("===============k->v映射在key重复的情况写法一===========");
        Map<String, BrowsingHistoryBO> browsingHistoryBOMap = list.stream().collect(Collectors.toMap(BrowsingHistoryBO::getPerson,
                Function.identity(), (x1, x2) -> x1));
        System.out.println("key重复的情况写法一:" + browsingHistoryBOMap);
        System.out.println("===============k->v映射在key重复的情况写法二===========");
        Map<Long, BrowsingHistoryBO> browsingHistoryBOMap2 =
                list.stream().collect(Collectors.toMap(e -> e.getBrowsId(),
                        e -> e, (x1, x2) -> x1));
        System.out.println("在key重复的情况写法二:" + browsingHistoryBOMap2);

        System.out.println("===============k->v映射在key唯一的情况===========");
        Map<Long, BrowsingHistoryBO> browsingHistoryBOMap3 =
                list.stream().collect(Collectors.toMap(BrowsingHistoryBO::getBrowsId, Function.identity()));
        System.out.println("k->v映射在key唯一的情况:" + browsingHistoryBOMap3);

        Map<String, List<BrowsingHistoryBO>> groupThenSort = list.stream()
                .filter(e -> e != null && e.getPerson() != null)// 这里是为了下面分组的key不为null，要是key为null会报错的
                .sorted(Comparator.comparing(BrowsingHistoryBO::getDateTime).reversed())
                .collect(Collectors.groupingBy(BrowsingHistoryBO::getPerson));
        System.out.println("先分组在排序:" + groupThenSort);
        //获取张三最近一次的访问时间
        groupThenSort.get("张三").stream().findFirst().ifPresent(
                x -> System.out.println("获取张三最近一次的访问时间:" + x.getDateTime()));


    }

    @Test
    public void toCurrentMapTest() {
        List<Student> menu = Arrays.asList(
                new Student("刘一", 721, true, Student.GradeType.THREE, "男"),
                new Student("陈二", 637, true, Student.GradeType.THREE, "男"),
                new Student("陈二", 639, true, Student.GradeType.THREE, "男"),
                new Student("陈二", 640, true, Student.GradeType.THREE, "女"),
                new Student("张三", 666, true, Student.GradeType.TWO, "男"),
                new Student("李四", 531, true, Student.GradeType.TWO, "女"),
                new Student("王五", 483, false, Student.GradeType.THREE, "女"),
                new Student("赵六", 367, true, Student.GradeType.THREE, "女"),
                new Student("孙七", 721, false, Student.GradeType.ONE, "女"));

        Optional.of(menu.stream()
                        .collect(Collectors.toConcurrentMap(Student::getName, Student::getTotalScore, (x1, x2) -> x1)))
                .ifPresent(e -> {
                    System.out.println(e);
                    System.out.println(e.getClass());
                });


        List<Student> student_sorted =
                menu.stream().sorted(Comparator.comparing(Student::getTotalScore).reversed()).collect(Collectors.toList());
        System.out.println("按成绩排序从高到低：" + student_sorted);

        List<Student> studentSortedThen =
                menu.stream().sorted(Comparator.comparing(Student::getTotalScore).thenComparing(Student::getName
                ).reversed()).collect(Collectors.toList());
        System.out.println("按成绩排序从高到低然后姓名：" + studentSortedThen);

        Map<Student.GradeType, List<Student>> collectByGrade =
                menu.stream().collect(Collectors.groupingBy(Student::getGradeType));
        System.out.println("按照年级分组" + collectByGrade);

        List<Student> students = collectByGrade.values().stream()
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
        System.out.println("多个数组合并为一个数组flatMap:" + students);


        List<Student> studentList = menu.stream().peek(i -> i.setTotalScore(i.getTotalScore() * 10)).collect(Collectors.toList());
        System.out.println("把每一个学生的分数*10返回list:" + studentList);

    }

    @Test
    public void summarizingTest() {
        List<String> list = Arrays.asList("123", "456", "789", "1101", "212121121", "asdaa", "3e3e3e", "2321eewr", "123");
        IntSummaryStatistics intSummary = list.stream().collect(Collectors.summarizingInt(String::length));
        LongSummaryStatistics longSummary = list.stream().limit(4).collect(Collectors.summarizingLong(Long::valueOf));
        DoubleSummaryStatistics doubleSummary = list.stream().limit(3).collect(Collectors.summarizingDouble(Double::valueOf));

        System.out.println(intSummary);
        System.out.println(longSummary);
        System.out.println(doubleSummary);
    }


}

